home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1999 / MacHack 1999.toast / The Hacks / OutOfContextMenus / Source / COutOfContextApp.cp < prev    next >
Encoding:
Text File  |  1999-06-25  |  19.2 KB  |  772 lines  |  [TEXT/CWIE]

  1. // ===========================================================================
  2. //    COutOfContextApp.cp                 ©1999 Eric Traut
  3. // ===========================================================================
  4.  
  5. #include "COutOfContextApp.h"
  6. #include "CShadowWindow.h"
  7. #include "TerminationUtils.h"
  8.  
  9. #include <LGrowZone.h>
  10. #include <PP_Messages.h>
  11. #include <PP_Resources.h>
  12. #include <PPobClasses.h>
  13. #include <UDrawingState.h>
  14. #include <UMemoryMgr.h>
  15. #include <URegistrar.h>
  16.  
  17. #include <LWindow.h>
  18. #include <LCaption.h>
  19.  
  20. #include <LowMem.h>
  21.  
  22. #include <Gestalt.h>
  23. #include <Patches.h>
  24. #include <Traps.h>
  25. #include <Resources.h>
  26. #include <MixedMode.h>
  27.  
  28. #include "WaitNextEventPatch.h"
  29. #include "CRebootBehavior.h"
  30. #include "CPongGameBehavior.h"
  31.  
  32. #define SUPPORT_PIG_LATIN            0
  33.  
  34. const PP_PowerPlant::ResIDT    wind_SampleWindow             = 128;
  35.  
  36. #if SUPPORT_PIG_LATIN
  37. const PP_PowerPlant::ResIDT    menu_ContextMenu1             = 6788;
  38. const PP_PowerPlant::ResIDT    menu_ContextMenu2             = 234;
  39. #else
  40. const PP_PowerPlant::ResIDT    menu_ContextMenu1             = 6789;
  41. #endif
  42.  
  43. enum
  44. {
  45.     kContextMenu1HelpIndex        = 1,
  46.     kContextMenu1Divider1,
  47.     kContextMenu1GaussianBlur,
  48.     kContextMenu1Invert,
  49.     kContextMenu1FlipHorizontal,
  50.     kContextMenu1FlipVertical,
  51.     kContextMenu1Compress,
  52.     kContextMenu1Duplicate,
  53.     kContextMenu1Restore,
  54. #if SUPPORT_PIG_LATIN
  55.     kContextMenu1Divider2,
  56.     kContextMenuIDCharSet,
  57. #endif
  58.     kContextMenu1Divider3,
  59.     kContextMenu1AdjustVBlank,
  60.     kContextMenu1NextSlide,
  61.     kContextMenu1NewGame,
  62.     kContextMenu1Divider4,
  63.     kContextMenu1Restart,
  64.     
  65.     kContextMenu2Latin            = 1,
  66.     kContextMenu2PigLatin
  67. };
  68.  
  69. COutOfContextApp *            COutOfContextApp::sOutOfContextApp         = NULL;
  70.  
  71. GetNextEventFilterUPP        COutOfContextApp::sChainedGNEFilter        = NULL;
  72. GetNextEventFilterUPP        COutOfContextApp::sNewGNEFilter            = NULL;
  73. Ptr                            COutOfContextApp::sGNEJumpIsland        = NULL;
  74. Boolean                        COutOfContextApp::sGNEPatchInstalled    = false;
  75. THz                            COutOfContextApp::sAppZone                = NULL;
  76. Boolean                        COutOfContextApp::sWNEPatchInstalled    = false;
  77. Handle                        COutOfContextApp::sWNEPatchHandle        = NULL;
  78. MenuHandle                    COutOfContextApp::sContextMenu1            = NULL;
  79. MenuHandle                    COutOfContextApp::sContextMenu2            = NULL;
  80. SndChannelPtr                COutOfContextApp::sSoundChannel            = NULL;
  81.  
  82.  
  83. class StZoneSaver
  84. {
  85.     public:
  86.         StZoneSaver(THz    inNewZone)
  87.         {
  88.             mSavedZone = ::GetZone();
  89.             ::SetZone(inNewZone);
  90.         }
  91.         
  92.         ~StZoneSaver(void)
  93.         {
  94.             ::SetZone(mSavedZone);
  95.         }
  96.     
  97.     private:
  98.         THz        mSavedZone;
  99. };
  100.  
  101.  
  102. // ===========================================================================
  103. //        • Main Program
  104. // ===========================================================================
  105.  
  106. int
  107. main(void)
  108. {
  109.     SetDebugThrow_(PP_PowerPlant::debugAction_Debugger);
  110.     SetDebugSignal_(PP_PowerPlant::debugAction_Debugger);
  111.  
  112.     PP_PowerPlant::InitializeHeap(3);
  113.     PP_PowerPlant::UQDGlobals::InitializeToolbox(&qd);
  114.  
  115.     new PP_PowerPlant::LGrowZone(20000);
  116.     COutOfContextApp    theApp;
  117.     theApp.Run();
  118.     
  119.     return 0;
  120. }
  121.  
  122.  
  123. // ---------------------------------------------------------------------------
  124. //        • COutOfContextApp
  125. // ---------------------------------------------------------------------------
  126.  
  127. COutOfContextApp::COutOfContextApp(void)
  128. {
  129.     RegisterClass_(PP_PowerPlant::LWindow);
  130.     RegisterClass_(PP_PowerPlant::LCaption);
  131.     
  132.     sAppZone = ::GetZone();
  133.     sWNEPatchHandle = ::Get1Resource(kWNEPatchRsrcType, kWNEPatchRsrcID);
  134.     Assert_(sWNEPatchHandle != NULL);
  135.  
  136.     ::DetachResource(sWNEPatchHandle);
  137.     ::MoveHHi(sWNEPatchHandle);
  138.     ::HLock(sWNEPatchHandle);
  139.     
  140.     sContextMenu1 = ::GetMenu(menu_ContextMenu1);
  141.     Assert_(sContextMenu1 != NULL);
  142.  
  143. #if SUPPORT_PIG_LATIN
  144.     sContextMenu2 = ::GetMenu(menu_ContextMenu2);
  145.     Assert_(sContextMenu2 != NULL);
  146. #endif SUPPORT_PIG_LATIN
  147.  
  148.     OSErr                err;
  149.     err = ::SndNewChannel(&sSoundChannel, sampledSynth, initMono + initNoInterp + initNoDrop, NULL);
  150.     Assert_(err == noErr);
  151. }
  152.  
  153.  
  154. // ---------------------------------------------------------------------------
  155. //        • ~COutOfContextApp
  156. // ---------------------------------------------------------------------------
  157.  
  158. COutOfContextApp::~COutOfContextApp(void)
  159. {
  160. }
  161.  
  162.  
  163. // ---------------------------------------------------------------------------
  164. //        • StartUp
  165. // ---------------------------------------------------------------------------
  166.  
  167. void
  168. COutOfContextApp::StartUp(void)
  169. {
  170.     sOutOfContextApp = this;
  171.     
  172.     InstallTearDownProc(OutOfContextTearDownProc);
  173.     InstallGNEFilter();
  174.     
  175.     CRebootBehavior::Initialize(sSoundChannel);
  176.     CPongGameBehavior::Initialize(sSoundChannel);
  177. }
  178.  
  179.  
  180. // ---------------------------------------------------------------------------
  181. //        • ObeyCommand
  182. // ---------------------------------------------------------------------------
  183.  
  184. Boolean
  185. COutOfContextApp::ObeyCommand(
  186.     PP_PowerPlant::CommandT        inCommand,
  187.     void *                        ioParam)
  188. {
  189.     Boolean        cmdHandled = true;
  190.  
  191.     switch (inCommand)
  192.     {
  193.         case PP_PowerPlant::cmd_New:
  194.             PP_PowerPlant::LWindow    *theWindow =
  195.                                     PP_PowerPlant::LWindow::CreateWindow(wind_SampleWindow, this);
  196.             ThrowIfNULL_(theWindow);
  197.             
  198.             theWindow->Show();
  199.             break;
  200.  
  201.         default:
  202.             cmdHandled = PP_PowerPlant::LApplication::ObeyCommand(inCommand, ioParam);
  203.             break;
  204.     }
  205.     
  206.     return cmdHandled;
  207. }
  208.  
  209.  
  210. // ---------------------------------------------------------------------------
  211. //        • FindCommandStatus
  212. // ---------------------------------------------------------------------------
  213.  
  214. void
  215. COutOfContextApp::FindCommandStatus(
  216.     PP_PowerPlant::CommandT    inCommand,
  217.     Boolean &                outEnabled,
  218.     Boolean &                outUsesMark,
  219.     PP_PowerPlant::Char16 &    outMark,
  220.     Str255                    outName)
  221. {
  222.  
  223.     switch (inCommand)
  224.     {
  225.         case PP_PowerPlant::cmd_New:
  226.             outEnabled = true;
  227.             break;
  228.  
  229.         default:
  230.             LApplication::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
  231.             break;
  232.     }
  233. }
  234.  
  235.  
  236.  
  237. // ---------------------------------------------------------------------------
  238. //        • OutOfContextTearDownProc                                [static]
  239. // ---------------------------------------------------------------------------
  240.  
  241. void
  242. COutOfContextApp::OutOfContextTearDownProc(void)
  243. {
  244.     if (COutOfContextApp::sOutOfContextApp != NULL)
  245.         COutOfContextApp::sOutOfContextApp->TearDownApp();
  246. }
  247.  
  248.  
  249. // ---------------------------------------------------------------------------
  250. //    • TearDownApp
  251. // ---------------------------------------------------------------------------
  252.  
  253. void
  254. COutOfContextApp::TearDownApp(void)
  255. {
  256.     if (sSoundChannel != NULL)
  257.         ::SndDisposeChannel(sSoundChannel, true);
  258.     
  259.     TearDownShadowWindows();
  260.     RemoveGNEFilter();
  261.     DeinstallWNEPatch();
  262. }
  263.  
  264.  
  265. // ---------------------------------------------------------------------------
  266. //    • AttemptQuitSelf
  267. // ---------------------------------------------------------------------------
  268.  
  269. Boolean
  270. COutOfContextApp::AttemptQuitSelf(
  271.     SInt32    inSaveOption)
  272. {
  273.     #pragma unused (inSaveOption)
  274.     
  275.     TearDownApp();
  276.     sOutOfContextApp = NULL;
  277.     
  278.     return true;
  279. }
  280.  
  281.  
  282. // ---------------------------------------------------------------------------
  283. //    • HandleContextualMenuClick
  284. // ---------------------------------------------------------------------------
  285.  
  286. void
  287. COutOfContextApp::HandleContextualMenuClick(
  288.     EventRecord *        ioEvent, 
  289.     Boolean *            ioResult)
  290. {
  291.     ThrowIfNULL_(sContextMenu1);
  292.  
  293. #if SUPPORT_PIG_LATIN
  294.     ThrowIfNULL_(sContextMenu2);
  295. #endif
  296.     
  297.     WindowPtr        clickedWindow;
  298.     SInt16            clickedPart;
  299.     
  300.     clickedPart = ::FindWindow(ioEvent->where, &clickedWindow);
  301.     if (clickedWindow != NULL && clickedPart == inContent)
  302.     {
  303.         CShadowWindow *        shadowWindow;
  304.         shadowWindow = LookUpWindowInShadowList(reinterpret_cast<CWindowRecord *>(clickedWindow));
  305.         
  306.         if (shadowWindow != NULL)
  307.         {
  308.             ::InsertMenu(sContextMenu1, hierMenu);
  309.  
  310. #if SUPPORT_PIG_LATIN
  311.             ::InsertMenu(sContextMenu2, hierMenu);
  312. #endif
  313.  
  314.             Boolean        enableRestore = shadowWindow->ShouldEnableRestoreMenu();
  315.  
  316.             if (enableRestore)
  317.                 ::EnableItem(sContextMenu1, kContextMenu1Restore);
  318.             else
  319.                 ::DisableItem(sContextMenu1, kContextMenu1Restore);
  320.  
  321.             ::EnableItem(sContextMenu1, kContextMenu1GaussianBlur);
  322.             ::EnableItem(sContextMenu1, kContextMenu1Invert);
  323.             ::EnableItem(sContextMenu1, kContextMenu1FlipHorizontal);
  324.             ::EnableItem(sContextMenu1, kContextMenu1FlipVertical);
  325. #if SUPPORT_PIG_LATIN
  326.             ::EnableItem(sContextMenu1, kContextMenuIDCharSet);
  327. #endif
  328.             ::EnableItem(sContextMenu1, kContextMenu1Compress);
  329.             ::EnableItem(sContextMenu1, kContextMenu1AdjustVBlank);
  330.             ::EnableItem(sContextMenu1, kContextMenu1Duplicate);
  331.             ::EnableItem(sContextMenu1, kContextMenu1NextSlide);
  332.             ::EnableItem(sContextMenu1, kContextMenu1NewGame);
  333.             ::EnableItem(sContextMenu1, kContextMenu1Restart);
  334.  
  335.             SInt32        result;
  336.             result = ::PopUpMenuSelect(sContextMenu1, ioEvent->where.v, ioEvent->where.h, 0);
  337.  
  338. #if SUPPORT_PIG_LATIN
  339.             ::DeleteMenu(menu_ContextMenu2);
  340. #endif
  341.             ::DeleteMenu(menu_ContextMenu1);
  342.  
  343.             switch (HiWord(result))
  344.             {
  345.                 case menu_ContextMenu1:
  346.                     switch (LoWord(result))
  347.                     {
  348.                         case kContextMenu1GaussianBlur:
  349.                             shadowWindow->SetIdleMenuAction(kShadowActionBlur);
  350.                             break;
  351.                         
  352.                         case kContextMenu1Invert:
  353.                             shadowWindow->SetIdleMenuAction(kShadowActionInvert);
  354.                             break;
  355.                                 
  356.                         case kContextMenu1FlipHorizontal:
  357.                             shadowWindow->SetIdleMenuAction(kShadowActionFlipH);
  358.                             break;
  359.                         
  360.                         case kContextMenu1FlipVertical:
  361.                             shadowWindow->SetIdleMenuAction(kShadowActionFlipV);
  362.                             break;
  363.                         
  364.                         case kContextMenu1Restore:
  365.                             shadowWindow->SetIdleMenuAction(kShadowActionRestore);
  366.                             break;
  367.                         
  368.                         case kContextMenu1Compress:
  369.                             shadowWindow->SetIdleMenuAction(kShadowActionCrash);
  370.                             break;
  371.                         
  372.                         case kContextMenu1AdjustVBlank:
  373.                             shadowWindow->SetIdleMenuAction(kShadowActionVBlank);
  374.                             break;
  375.                         
  376.                         case kContextMenu1Duplicate:
  377.                             shadowWindow->SetIdleMenuAction(kShadowActionDuplicate);
  378.                             break;
  379.                         
  380.                         case kContextMenu1NextSlide:
  381.                             shadowWindow->SetIdleMenuAction(kShadowActionNextSlide);
  382.                             break;
  383.                         
  384.                         case kContextMenu1NewGame:
  385.                             shadowWindow->SetIdleMenuAction(kShadowActionGame);
  386.                             break;
  387.                         
  388.                         case kContextMenu1Restart:
  389.                             shadowWindow->SetIdleMenuAction(kShadowActionReboot);
  390.                             break;
  391.                     }
  392.                     break;
  393.                 
  394. #if SUPPORT_PIG_LATIN
  395.                 case menu_ContextMenu2:
  396.                     switch (LoWord(result))
  397.                     {
  398.                         case kContextMenu2Latin:
  399.                             shadowWindow->SetIdleMenuAction(kShadowActionRestore);
  400.                             break;
  401.                         
  402.                         case kContextMenu2PigLatin:
  403.                             shadowWindow->SetIdleMenuAction(kShadowActionPigLatin);
  404.                             break;
  405.                     }
  406.                     break;
  407. #endif
  408.                 }
  409.  
  410.             *ioResult = false;
  411.         }
  412.     }
  413. }
  414.  
  415.  
  416. // ---------------------------------------------------------------------------
  417. //    • DoFinderGNEFilter
  418. // ---------------------------------------------------------------------------
  419.  
  420. void
  421. COutOfContextApp::DoFinderGNEFilter(
  422.     EventRecord *        ioEvent, 
  423.     Boolean *            ioResult)
  424. {
  425.     // Temporarily set the zone to our app. We don't want to
  426.     // be allocating out of our "guest's" heap.
  427.     StZoneSaver        saveZone(sAppZone);
  428.     
  429.     try
  430.     {
  431.         // Update the list of all the open windows in the Finder
  432.         UpdateShadowWindowList();
  433.  
  434.         if (ioEvent->what == mouseDown &&
  435.             (ioEvent->modifiers & controlKey) != 0)
  436.         {
  437.             HandleContextualMenuClick(ioEvent, ioResult);
  438.         }
  439.         else
  440.         {
  441.             WindowPtr        frontWindow = ::FrontWindow();
  442.             CShadowWindow *    frontShadow = LookUpWindowInShadowList(reinterpret_cast<CWindowRecord *>(frontWindow));
  443.  
  444.             if (frontShadow != NULL)
  445.                 frontShadow->HandleEvent(ioEvent, ioResult);
  446.  
  447.             // Give each of the shadow windows some time
  448.             GiveShadowWindowsTime(true);
  449.         }
  450.     }
  451.     catch (...)
  452.     {
  453.         // Don't throw any exceptions through the GNE filter
  454.     }
  455. }
  456.  
  457.  
  458. // ---------------------------------------------------------------------------
  459. //    • GNEFilterPatch                                [static]
  460. // ---------------------------------------------------------------------------
  461.  
  462. pascal void
  463. COutOfContextApp::GNEFilterPatch(
  464.     EventRecord *        ioEvent, 
  465.     Boolean *            ioResult)
  466. {
  467.     OSErr                    error;
  468.     ProcessInfoRec            processInfo;
  469.     ProcessSerialNumber        psn;
  470.     
  471.     error = ::GetCurrentProcess(&psn);
  472.     Assert_(error == noErr);
  473.     
  474.     processInfo.processInfoLength = sizeof(processInfo);
  475.     processInfo.processName = NULL;
  476.     processInfo.processAppSpec = NULL;
  477.     error = ::GetProcessInformation(&psn, &processInfo);
  478.     Assert_(error == noErr);
  479.  
  480.     // Is this the Finder? If so, we've got some things to do.
  481.     if (processInfo.processSignature == 'MACS')
  482.     {
  483.         if (!sWNEPatchInstalled)
  484.             InstallWNEPatch();
  485.     
  486.         COutOfContextApp::sOutOfContextApp->DoFinderGNEFilter(ioEvent, ioResult);
  487.     }
  488.     
  489.     // Call through to the next one in the chain
  490.     if (sChainedGNEFilter != NULL)
  491.         CallGetNextEventFilterProc(sChainedGNEFilter, ioEvent, ioResult);
  492. }
  493.  
  494.  
  495. // ---------------------------------------------------------------------------
  496. //    • InstallWNEPatch                                        [static]
  497. // ---------------------------------------------------------------------------
  498.  
  499. void
  500. COutOfContextApp::InstallWNEPatch(void)
  501. {
  502.     if (!sWNEPatchInstalled)
  503.     {
  504.         sWNEPatchInstalled = true;
  505.  
  506.         WNEPatchInfo *        wnePatchInfo;
  507.         // First, see if there's already a copy of the
  508.         // patch hanging around in the system heap. If so, 
  509.         // just turn it on.
  510.         if (Gestalt(gestaltWNEPatch, (long *)&wnePatchInfo) == noErr)
  511.         {
  512.             // See if the Finder's WNE is still wired to our patch.
  513.             // If so, we'll just enable it.
  514.             UniversalProcPtr    curWNEPatch = ::GetToolTrapAddress(_WaitNextEvent);
  515.             if (curWNEPatch == (UniversalProcPtr)wnePatchInfo->fPatchEntry)
  516.             {
  517.                 wnePatchInfo->fPatchActive = true;
  518.                 return;
  519.             }
  520.         }
  521.         
  522.         // Call the patch to have it install itself
  523.         (void) CallUniversalProc(    (UniversalProcPtr)*sWNEPatchHandle,
  524.                                     kPascalStackBased);
  525.     }
  526. }
  527.  
  528.  
  529. // ---------------------------------------------------------------------------
  530. //    • DeinstallWNEPatch                                        [static]
  531. // ---------------------------------------------------------------------------
  532.  
  533. void
  534. COutOfContextApp::DeinstallWNEPatch(void)
  535. {
  536.     // We can't unpatch ourselves here, but we can
  537.     // turn ourselves off.
  538.     if (sWNEPatchInstalled)
  539.     {
  540.         sWNEPatchInstalled = false;
  541.  
  542.         WNEPatchInfo *        wnePatchInfo;
  543.  
  544.         // First, see if there's already a copy of the
  545.         // patch hanging around in the system heap. If so, 
  546.         // just turn it on.
  547.         if (Gestalt(gestaltWNEPatch, (long *)&wnePatchInfo) == noErr)
  548.             wnePatchInfo->fPatchActive = false;
  549.     }
  550. }
  551.  
  552.  
  553. // ---------------------------------------------------------------------------
  554. //    • InstallGNEFilter
  555. // ---------------------------------------------------------------------------
  556.  
  557. void
  558. COutOfContextApp::InstallGNEFilter(void)
  559. {
  560.     sGNEJumpIsland = ::NewPtrSysClear(6);
  561.     ThrowIfNULL_(sGNEJumpIsland);
  562.     
  563.     sNewGNEFilter = NewGetNextEventFilterProc(COutOfContextApp::GNEFilterPatch);
  564.     ThrowIfNULL_(sNewGNEFilter);
  565.     
  566.     // Fill in the jump instruction (JMP $XXXXXXXXL)
  567.     *(UInt16 *)sGNEJumpIsland = 0x4EF9;
  568.     *(GetNextEventFilterUPP *)(sGNEJumpIsland + 2) = sNewGNEFilter;
  569.  
  570.     // We just modified code, so we need to flush the cache
  571.     Flush68KCodeCache();
  572.     
  573.     sChainedGNEFilter = LMGetGNEFilter();
  574.     LMSetGNEFilter((GetNextEventFilterUPP)sGNEJumpIsland);
  575.     
  576.     sGNEPatchInstalled = true;
  577. }
  578.  
  579.  
  580. // ---------------------------------------------------------------------------
  581. //    • RemoveGNEFilter
  582. // ---------------------------------------------------------------------------
  583.  
  584. void
  585. COutOfContextApp::RemoveGNEFilter(void)
  586. {
  587.     if (sGNEPatchInstalled)
  588.     {
  589.         // Can we just unchain, or do we need to 
  590.         // leave the island in place?
  591.         if (LMGetGNEFilter() == (GetNextEventFilterUPP)sGNEJumpIsland)
  592.         {
  593.             LMSetGNEFilter(sChainedGNEFilter);
  594.             
  595.             ::DisposeRoutineDescriptor(sNewGNEFilter);
  596.             ::DisposePtr((Ptr)sGNEJumpIsland);
  597.         }
  598.         else
  599.         {
  600.             *(GetNextEventFilterUPP *)(sGNEJumpIsland + 2) = sChainedGNEFilter;
  601.             
  602.             // We just modified code, so we need to flush the cache
  603.             Flush68KCodeCache();
  604.         }
  605.         
  606.         sGNEPatchInstalled = false;
  607.     }
  608. }
  609.  
  610.  
  611. /*------------------------------------------------------------------
  612.     Flush68KCodeCache
  613.     
  614.     This function flushes the 68K emulator code cache.
  615. ------------------------------------------------------------------*/
  616.  
  617. void
  618. COutOfContextApp::Flush68KCodeCache(void)
  619. {
  620.     static const UInt16 s68KCode[] = 
  621.     {
  622.         0xA0BD,        // vCacheFlush
  623.         0x4E75        // RTS
  624.     };
  625.  
  626.     CallUniversalProc((UniversalProcPtr)s68KCode, kPascalStackBased);
  627. }
  628.  
  629.  
  630. /*------------------------------------------------------------------
  631.     UpdateShadowWindowList
  632.     
  633.     Creates a list of shadow window objects.
  634. ------------------------------------------------------------------*/
  635.  
  636. void
  637. COutOfContextApp::UpdateShadowWindowList(void)
  638. {
  639.     TArrayIterator<CShadowWindow *>        iterator(mShadowWindowList);
  640.     CShadowWindow *                        curWindow;
  641.     
  642.     // Clear all the "visited" flags
  643.     while (iterator.Next(curWindow))
  644.         curWindow->ClearVisitedFlag();
  645.     
  646.     // Add in all of the new windows
  647.     CWindowRecord *        curMacWindow;
  648.     curMacWindow = reinterpret_cast<CWindowRecord *>(LMGetWindowList());
  649.     
  650.     while (curMacWindow != NULL)
  651.     {
  652.         // Do we already know about this window?
  653.         curWindow = LookUpWindowInShadowList(curMacWindow);
  654.         
  655.         if (curWindow == NULL)
  656.         {
  657.             curWindow = new CShadowWindow(curMacWindow);
  658.             if (curWindow != NULL)
  659.                 mShadowWindowList.AddItem(curWindow);
  660.         }
  661.         
  662.         if (curWindow != NULL)
  663.             curWindow->SetVisitedFlag();
  664.         
  665.         // Go to next window in Mac's window list
  666.         curMacWindow = reinterpret_cast<CWindowRecord *>(curMacWindow->nextWindow);
  667.     }
  668.     
  669.     // Delete all the unvisited flags
  670.     iterator.ResetTo(LArrayIterator::from_Start);
  671.     while (iterator.Next(curWindow))
  672.     {
  673.         if (!curWindow->WasVisited())
  674.         {
  675.             delete curWindow;
  676.             mShadowWindowList.RemoveItemsAt(1, iterator.GetCurrentIndex());
  677.         }
  678.     }
  679. }
  680.  
  681.  
  682. /*------------------------------------------------------------------
  683.     LookUpWindowInShadowList
  684.     
  685.     Searches the shadow list for a specified Mac window.
  686. ------------------------------------------------------------------*/
  687.  
  688. CShadowWindow *
  689. COutOfContextApp::LookUpWindowInShadowList(
  690.     const CWindowRecord *        inMacWindow)
  691. {
  692.     TArrayIterator<CShadowWindow *>        iterator(mShadowWindowList);
  693.     CShadowWindow *                        curWindow;
  694.     
  695.     // Clear all the "visited" flags
  696.     while (iterator.Next(curWindow))
  697.     {
  698.         if (curWindow->GetMacWindow() == inMacWindow)
  699.             return curWindow;
  700.     }
  701.     
  702.     return NULL;
  703. }
  704.  
  705.  
  706. /*------------------------------------------------------------------
  707.     GiveShadowWindowsTime
  708.     
  709.     Calles each of the installed shadow window objects to
  710.     give them time to "do their stuff".
  711. ------------------------------------------------------------------*/
  712.  
  713. void
  714. COutOfContextApp::GiveShadowWindowsTime(
  715.     Boolean        inGNETime)
  716. {
  717.     // Temporarily set the zone to our app. We don't want to
  718.     // be allocating out of our "guest's" heap.
  719.     StZoneSaver        saveZone(sAppZone);
  720.  
  721.     StGDeviceSaver                        savedPort;
  722.     TArrayIterator<CShadowWindow *>        iterator(mShadowWindowList);
  723.     CShadowWindow *                        curWindow;
  724.     
  725.     while (iterator.Next(curWindow))
  726.         curWindow->DoIdleTask(inGNETime);
  727. }
  728.  
  729.  
  730. /*------------------------------------------------------------------
  731.     LookUpShadowWindow
  732.     
  733.     Searches the shadow window list looking for a match.
  734. ------------------------------------------------------------------*/
  735.  
  736. CShadowWindow *
  737. COutOfContextApp::LookUpShadowWindow(
  738.     CWindowRecord *        inMacWindow)
  739. {
  740.     TArrayIterator<CShadowWindow *>        iterator(mShadowWindowList);
  741.     CShadowWindow *                        curWindow;
  742.     
  743.     while (iterator.Next(curWindow))
  744.     {
  745.         if (curWindow->GetMacWindow() == inMacWindow)
  746.             return curWindow;
  747.     }
  748.     
  749.     return NULL;
  750. }
  751.  
  752.  
  753. /*------------------------------------------------------------------
  754.     TearDownShadowWindows
  755.     
  756.     Detaches from all the windows. Let's hope that the window
  757.     list has not changed since the last time we synched up!
  758. ------------------------------------------------------------------*/
  759.  
  760. void
  761. COutOfContextApp::TearDownShadowWindows(void)
  762. {
  763.     TArrayIterator<CShadowWindow *>        iterator(mShadowWindowList);
  764.     CShadowWindow *                        curWindow;
  765.     
  766.     while (iterator.Next(curWindow))
  767.         curWindow->DetachBehavior();
  768. }
  769.  
  770.  
  771.  
  772.